<!--
 * new page
 * @author: YK
 * @since: 2024-01-16
 * index.vue
-->
<template>
  <el-form
    ref="formRef"
    v-if="model"
    v-bind="$attrs"
    :model="model"
    :rules="rules"
    :validate-on-rule-change="false"
  >
    <template v-for="(item, index) in options">
      <el-form-item
        v-if="!item.children||!(item.children!?.length)"
        :label="item.label"
        :prop="item.prop"
        :key="index"
      >
        <component
          v-if="item.type != 'upload' && item.type != 'editor'"
          v-model="model[item.prop!]"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
        ></component>
        <el-upload
          v-else-if="item.type == 'upload'"
          v-bind="item.uploadAttrs"
          :on-preview="onPreview"
          :on-remove="onRemove"
          :on-success="onSuccess"
          :on-error="onError"
          :on-progress="onProgress"
          :on-change="onChange"
          :on-before-remove="onBeforeRemove"
          :before-upload="onBeforeUpload"
          :https-request="HttpRequest"
          :on-exceed="onExtract"
          ref="uploadRef"
        >
          <slot name="uploadArea"></slot>
          <slot name="tip"></slot>
        </el-upload>
        <div v-else-if="item.type == 'editor'">
          <Toolbar
            :style="{ ...item.editorattrs?.toolbarStyle }"
            :editor="editorRef"
            :defaultConfig="item.editorattrs?.toolbarConfig"
            mode="default"
          />
          <Editor
            :style="{
              height: '500px',
              overflowY: 'hidden',
              border: '1px solid #ccc',
              ...item.editorattrs?.editorStyle,
            }"
            v-model="model[item.prop!]"
            :defaultConfig="item.editorattrs?.editorConfig"
            mode="default"
            @onCreated="handleCreated"
          />
        </div>
      </el-form-item>
      <el-form-item
        v-if="item.children&&(item.children!?.length)"
        :label="item.label"
        :prop="item.prop"
        :key="index"
      >
        <component
          v-model="model[item.prop!]"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
        >
          <component
            v-for="(child, i) in item.children"
            :key="i"
            :label="child.label"
            :value="child.value"
            :is="`el-${child.type}`"
          ></component>
        </component>
      </el-form-item>
    </template>
    <el-form-item>
      <slot name="action" :form="formRef" :model="model"></slot>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
import { FormOptions } from "./types/types";
import { ref, onMounted, watch, onBeforeUnmount, shallowRef } from "vue";
import cloneDeep from "lodash/cloneDeep";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import aliUpload from "./aliUpload";
import type { FormInstance, UploadInstance } from "element-plus";
import "@wangeditor/editor/dist/css/style.css";
const props = withDefaults(
  defineProps<{ options: FormOptions[]; HttpRequest: () => void }>(),
  {
    options: () => [],
    HttpRequest: () => {},
  }
);
const emit = defineEmits<{
  (e: "on-upload", value: any): void;
  (e: "on-preview", value: any): void;
  (e: "on-remove", value: any): void;
  (e: "on-success", value: any): void;
  (e: "on-error", value: any): void;
  (e: "on-progress", value: any): void;
  (e: "on-change", value: any): void;
  (e: "on-before-remove", value: any): void;
  (e: "before-upload", value: any): void;
  (e: "https-request", value: any): void;
  (e: "on-extract", file: any): void;
  (e: "on-before-upload", file: any): void;
  (e: "on-http-request"): void;
}>();
const formRef = ref<FormInstance>();
const model = ref<any>(null);
const rules = ref<any>(null);
const uploadRef = ref<UploadInstance>();
// 初始化表单
const initForm = () => {
  if (!props.options.length) return;
  // 初始化表单验证规则
  // 初始化表单数据
  let m: any = {};
  let r: any = {};
  props.options.forEach((item: FormOptions) => {
    m[item.prop!] = item.value;
    r[item.prop!] = item.rules;
  });
  model.value = cloneDeep(m);
  rules.value = cloneDeep(r);
  // console.log(rules.value, model.value);
};
onMounted(() => {
  initForm();
});
watch(
  () => props.options,
  () => {
    //如果传入的数据变化需要重新初始化
    initForm();
  },
  { deep: true }
);
const onPreview = (file: File) => {
  emit("on-preview", { file });
};
const onRemove = (file: File, fileList: FileList) => {
  console.log(file, fileList, "0099");

  emit("on-remove", { file, fileList });
};
const onSuccess = (response: any, file: File, fileList: FileList) => {
  // 处理上传成功的逻辑
  let uploadItem: FormOptions | undefined = props.options.find(
    (item: FormOptions) => item.type === "upload"
  );
  console.log(uploadItem, "===>>");

  if (!uploadItem) return;
  model.value[uploadItem.prop!] = { response, file, fileList };
  emit("on-success", { response, file, fileList });
};
const onChange = (file: File, fileList: FileList) => {
  emit("on-change", { file, fileList });
};
const onProgress = (event: any, file: File, fileList: FileList) => {
  emit("on-progress", { event, file, fileList });
};
const onBeforeRemove = (file: File, fileList: FileList) => {
  emit("on-before-remove", { file, fileList });
};
const onError = (err: any, file: File, fileList: FileList) => {
  emit("on-error", { err, file, fileList });
};
const onBeforeUpload = (file: File) => {
  emit("on-before-upload", { file });
};

const onExtract = (file: File, fileList: FileList) => {
  console.log(file, fileList);
  emit("on-extract", { file, fileList });
};
// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef();

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
onMounted(() => {
  let editorItem: FormOptions | undefined = props.options.find(
    (item: FormOptions) => item.type === "editor"
  );
  if (editorItem) {
    editorItem.editorattrs!.editorConfig!.MENU_CONF.uploadImage = {
      async customUpload(file: any, insertFn: any) {
        const res: any = await aliUpload(file);
        insertFn(res);
      },
    };
  }
});
const handleCreated = (editor: any) => {
  editorRef.value = editor; // 记录 editor 实例，重要！
};

//重置表单
const resetForm = (formEl: FormInstance | undefined) => {
  if (formEl) {
    formEl.resetFields();
  }
  if (props.options?.length > 0) {
    //处理富文本清空问题
    let editorItem: FormOptions | undefined = props.options.find(
      (item: FormOptions) => item.type === "editor"
    );
    if (editorItem) {
      model[editorItem.prop!] = editorItem.value;
    }
    if (uploadRef.value) {
      uploadRef.value!.clearFiles();
    }
  }
};
//表单验证
const validate = () => {
  return formRef.value!.validate();
};
//获取表你打数据的方法
const getFormDate = () => {
  return model.value;
};
defineExpose({
  resetForm,
  validate,
  getFormDate,
});
</script>

<style scoped lang="scss">
::v-deep .el-upload {
  display: block;
}
</style>
